From: Christian Limpach Date: Tue, 3 Apr 2007 12:22:37 +0000 (+0100) Subject: [hvm] Keep track of time offset between domain time and dom0 time. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~15270^2 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks://%22Dat/%22http:/www.example.com/cgi/%22https:/%22bookmarks:/%22Dat?a=commitdiff_plain;h=2bdbd3e1939805676f7b025a58d23cea942fe042;p=xen.git [hvm] Keep track of time offset between domain time and dom0 time. On each rtc time update from the hvm domain, we send an ioreq request to qemu which then updates the time offset xenstore entry. The time offset is preserved across reboot and can be set on domain creation by setting the rtc_timeoffset variable in a config file. From: Andrei Petrov Signed-off-by: Christian Limpach --- diff --git a/tools/examples/xmexample.hvm b/tools/examples/xmexample.hvm index 33ce3203d3..06662a0d17 100644 --- a/tools/examples/xmexample.hvm +++ b/tools/examples/xmexample.hvm @@ -179,6 +179,10 @@ serial='pty' #localtime=1 +#----------------------------------------------------------------------------- +# set the real time clock offset in seconds [default=0 i.e. same as dom0] +#rtc_timeoffset=3600 + #----------------------------------------------------------------------------- # start in full screen #full-screen=1 diff --git a/tools/ioemu/target-i386-dm/helper2.c b/tools/ioemu/target-i386-dm/helper2.c index 17261e632d..8b98e8a184 100644 --- a/tools/ioemu/target-i386-dm/helper2.c +++ b/tools/ioemu/target-i386-dm/helper2.c @@ -74,6 +74,8 @@ int vcpus = 1; int xc_handle; +long time_offset = 0; + shared_iopage_t *shared_page = NULL; #define BUFFER_IO_MAX_DELAY 100 @@ -439,6 +441,34 @@ void cpu_ioreq_xor(CPUState *env, ioreq_t *req) req->data = tmp1; } +void timeoffset_get() +{ + char *p; + + p = xenstore_vm_read(domid, "rtc/timeoffset", NULL); + if (!p) + return; + + if (sscanf(p, "%ld", &time_offset) == 1) + fprintf(logfile, "Time offset set %ld\n", time_offset); + else + time_offset = 0; + + xc_domain_set_time_offset(xc_handle, domid, time_offset); + + free(p); +} + +void cpu_ioreq_timeoffset(CPUState *env, ioreq_t *req) +{ + char b[64]; + + time_offset += (ulong)req->data; + + sprintf(b, "%ld", time_offset); + xenstore_vm_write(domid, "rtc/timeoffset", b); +} + void cpu_ioreq_xchg(CPUState *env, ioreq_t *req) { unsigned long tmp1; @@ -478,6 +508,9 @@ void __handle_ioreq(CPUState *env, ioreq_t *req) case IOREQ_TYPE_XCHG: cpu_ioreq_xchg(env, req); break; + case IOREQ_TYPE_TIMEOFFSET: + cpu_ioreq_timeoffset(env, req); + break; default: hw_error("Invalid ioreq type 0x%x\n", req->type); } diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index 66174de66f..4ec5e0817d 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -6670,6 +6670,9 @@ int main(int argc, char **argv) } free(page_array); #endif + + timeoffset_get(); + #else /* !CONFIG_DM */ phys_ram_base = qemu_vmalloc(phys_ram_size); diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index a6b53aa312..4ef250f766 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -1276,6 +1276,12 @@ int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle, const char *inst, const char *token); +int xenstore_vm_write(int domid, char *key, char *val); +char *xenstore_vm_read(int domid, char *key, int *len); + +/* helper2.c */ +extern long time_offset; +void timeoffset_get(void); /* xen_platform.c */ void pci_xen_platform_init(PCIBus *bus); diff --git a/tools/ioemu/xenstore.c b/tools/ioemu/xenstore.c index 26063f5a93..77819cea67 100644 --- a/tools/ioemu/xenstore.c +++ b/tools/ioemu/xenstore.c @@ -567,3 +567,72 @@ int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle, return rc; } + +char *xenstore_vm_read(int domid, char *key, int *len) +{ + char *buf = NULL, *path = NULL, *value = NULL; + + if (xsh == NULL) + goto out; + + path = xs_get_domain_path(xsh, domid); + if (path == NULL) { + fprintf(logfile, "xs_get_domain_path(%d): error\n", domid); + goto out; + } + + pasprintf(&buf, "%s/vm", path); + free(path); + path = xs_read(xsh, XBT_NULL, buf, NULL); + if (path == NULL) { + fprintf(logfile, "xs_read(%s): read error\n", buf); + goto out; + } + + pasprintf(&buf, "%s/%s", path, key); + value = xs_read(xsh, XBT_NULL, buf, len); + if (value == NULL) { + fprintf(logfile, "xs_read(%s): read error\n", buf); + goto out; + } + + out: + free(path); + free(buf); + return value; +} + +int xenstore_vm_write(int domid, char *key, char *value) +{ + char *buf = NULL, *path = NULL; + int rc = -1; + + if (xsh == NULL) + goto out; + + path = xs_get_domain_path(xsh, domid); + if (path == NULL) { + fprintf(logfile, "xs_get_domain_path(%d): error\n"); + goto out; + } + + pasprintf(&buf, "%s/vm", path); + free(path); + path = xs_read(xsh, XBT_NULL, buf, NULL); + if (path == NULL) { + fprintf(logfile, "xs_read(%s): read error\n", buf); + goto out; + } + + pasprintf(&buf, "%s/%s", path, key); + rc = xs_write(xsh, XBT_NULL, buf, value, strlen(value)); + if (rc) { + fprintf(logfile, "xs_write(%s, %s): write error\n", buf, key); + goto out; + } + + out: + free(path); + free(buf); + return rc; +} diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index e36e89a0df..a4a9d43fe5 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -118,7 +118,7 @@ LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG) # Platform configuration keys. XENAPI_PLATFORM_CFG = [ 'acpi', 'apic', 'boot', 'device_model', 'display', 'fda', 'fdb', 'keymap', 'isa', 'localtime', - 'nographic', 'pae', 'serial', 'sdl', + 'nographic', 'pae', 'rtc_timeoffset', 'serial', 'sdl', 'soundhw','stdvga', 'usb', 'usbdevice', 'vnc', 'vncconsole', 'vncdisplay', 'vnclisten', 'vncpasswd', 'vncunused', 'xauthority'] @@ -203,6 +203,7 @@ LEGACY_CFG_TYPES = { 'on_xend_stop': str, 'on_xend_start': str, 'online_vcpus': int, + 'rtc/timeoffset': str, } # Values that should be stored in xenstore's /vm/ that is used diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 7ba20fb566..425776ce12 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -859,7 +859,8 @@ class XendDomainInfo: # Check whether values in the configuration have # changed in Xenstore. - cfg_vm = ['name', 'on_poweroff', 'on_reboot', 'on_crash'] + cfg_vm = ['name', 'on_poweroff', 'on_reboot', 'on_crash', + 'rtc/timeoffset'] vm_details = self._readVMDetails([(k,XendConfig.LEGACY_CFG_TYPES[k]) for k in cfg_vm]) @@ -888,6 +889,11 @@ class XendDomainInfo: self.info.update_with_image_sxp(sxp.from_string(image_sxp)) changed = True + # Check if the rtc offset has changes + if vm_details.get("rtc/timeoffset", 0) != self.info["platform"].get("rtc_timeoffset", 0): + self.info["platform"]["rtc_timeoffset"] = vm_details.get("rtc/timeoffset", 0) + changed = True + if changed: # Update the domain section of the store, as this contains some # parameters derived from the VM configuration. diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index d9e850ccc9..835a5d8060 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -256,9 +256,12 @@ class HVMImageHandler(ImageHandler): self.xauthority = vmConfig['platform'].get('xauthority') self.vncconsole = vmConfig['platform'].get('vncconsole') + rtc_timeoffset = vmConfig['platform'].get('rtc_timeoffset') + self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)), ("image/device-model", self.device_model), ("image/display", self.display)) + self.vm.storeVm(("rtc/timeoffset", rtc_timeoffset)) self.pid = None diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 0ae94d83c4..1411f9be89 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -186,6 +186,10 @@ gopts.var('cpus', val='CPUS', fn=set_value, default=None, use="CPUS to run the domain on.") +gopts.var('rtc_timeoffset', val='RTC_TIMEOFFSET', + fn=set_value, default="0", + use="Set RTC offset.") + gopts.var('pae', val='PAE', fn=set_int, default=1, use="Disable or enable PAE of HVM domain.") @@ -717,7 +721,7 @@ def configure_hvm(config_image, vals): args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw', 'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten', - 'sdl', 'display', 'xauthority', + 'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'acpi', 'apic', 'usb', 'usbdevice', 'keymap' ] for a in args: if a in vals.__dict__ and vals.__dict__[a] is not None: diff --git a/xen/arch/x86/hvm/intercept.c b/xen/arch/x86/hvm/intercept.c index 3de58812c3..fb8497a996 100644 --- a/xen/arch/x86/hvm/intercept.c +++ b/xen/arch/x86/hvm/intercept.c @@ -155,28 +155,13 @@ static inline void hvm_mmio_access(struct vcpu *v, } } -int hvm_buffered_io_intercept(ioreq_t *p) +int hvm_buffered_io_send(ioreq_t *p) { struct vcpu *v = current; spinlock_t *buffered_io_lock; buffered_iopage_t *buffered_iopage = (buffered_iopage_t *)(v->domain->arch.hvm_domain.buffered_io_va); unsigned long tmp_write_pointer = 0; - int i; - - /* ignore READ ioreq_t! */ - if ( p->dir == IOREQ_READ ) - return 0; - - for ( i = 0; i < HVM_BUFFERED_IO_RANGE_NR; i++ ) { - if ( p->addr >= hvm_buffered_io_ranges[i]->start_addr && - p->addr + p->size - 1 < hvm_buffered_io_ranges[i]->start_addr + - hvm_buffered_io_ranges[i]->length ) - break; - } - - if ( i == HVM_BUFFERED_IO_RANGE_NR ) - return 0; buffered_io_lock = &v->domain->arch.hvm_domain.buffered_io_lock; spin_lock(buffered_io_lock); @@ -205,6 +190,27 @@ int hvm_buffered_io_intercept(ioreq_t *p) return 1; } +int hvm_buffered_io_intercept(ioreq_t *p) +{ + int i; + + /* ignore READ ioreq_t! */ + if ( p->dir == IOREQ_READ ) + return 0; + + for ( i = 0; i < HVM_BUFFERED_IO_RANGE_NR; i++ ) { + if ( p->addr >= hvm_buffered_io_ranges[i]->start_addr && + p->addr + p->size - 1 < hvm_buffered_io_ranges[i]->start_addr + + hvm_buffered_io_ranges[i]->length ) + break; + } + + if ( i == HVM_BUFFERED_IO_RANGE_NR ) + return 0; + + return hvm_buffered_io_send(p); +} + int hvm_mmio_intercept(ioreq_t *p) { struct vcpu *v = current; diff --git a/xen/arch/x86/hvm/platform.c b/xen/arch/x86/hvm/platform.c index 185a7c2f55..d8a751bd1d 100644 --- a/xen/arch/x86/hvm/platform.c +++ b/xen/arch/x86/hvm/platform.c @@ -921,6 +921,26 @@ static void send_mmio_req(unsigned char type, unsigned long gpa, hvm_send_assist_req(v); } +void send_timeoffset_req(unsigned long timeoff) +{ + ioreq_t p[1]; + + if ( timeoff == 0 ) + return; + + memset(p, 0, sizeof(*p)); + + p->type = IOREQ_TYPE_TIMEOFFSET; + p->size = 4; + p->dir = IOREQ_WRITE; + p->data = timeoff; + + p->state = STATE_IOREQ_READY; + + if ( !hvm_buffered_io_send(p) ) + printk("Unsuccessful timeoffset update\n"); +} + static void mmio_operands(int type, unsigned long gpa, struct hvm_io_op *mmio_op, unsigned char op_size) diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c index 036eba7bfe..1b18dca204 100644 --- a/xen/arch/x86/hvm/rtc.c +++ b/xen/arch/x86/hvm/rtc.c @@ -157,6 +157,10 @@ static inline int from_bcd(RTCState *s, int a) static void rtc_set_time(RTCState *s) { struct tm *tm = &s->current_tm; + unsigned long before, after; /* XXX s_time_t */ + + before = mktime(tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); tm->tm_sec = from_bcd(s, s->hw.cmos_data[RTC_SECONDS]); tm->tm_min = from_bcd(s, s->hw.cmos_data[RTC_MINUTES]); @@ -168,6 +172,10 @@ static void rtc_set_time(RTCState *s) tm->tm_mday = from_bcd(s, s->hw.cmos_data[RTC_DAY_OF_MONTH]); tm->tm_mon = from_bcd(s, s->hw.cmos_data[RTC_MONTH]) - 1; tm->tm_year = from_bcd(s, s->hw.cmos_data[RTC_YEAR]) + 100; + + after = mktime(tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + send_timeoffset_req(after - before); } static void rtc_copy_date(RTCState *s) diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index daba20ff39..d31fa17984 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -573,7 +573,7 @@ static void init_platform_timer(void) * machines were long is 32-bit! (However, as time_t is signed, we * will already get problems at other places on 2038-01-19 03:14:08) */ -static inline unsigned long +unsigned long mktime (unsigned int year, unsigned int mon, unsigned int day, unsigned int hour, unsigned int min, unsigned int sec) diff --git a/xen/include/asm-x86/hvm/io.h b/xen/include/asm-x86/hvm/io.h index 092b037516..cf46b0cb6d 100644 --- a/xen/include/asm-x86/hvm/io.h +++ b/xen/include/asm-x86/hvm/io.h @@ -127,6 +127,7 @@ static inline int hvm_portio_intercept(ioreq_t *p) } extern int hvm_mmio_intercept(ioreq_t *p); +extern int hvm_buffered_io_send(ioreq_t *p); extern int hvm_buffered_io_intercept(ioreq_t *p); static inline int register_portio_handler( @@ -145,6 +146,7 @@ static inline int irq_masked(unsigned long eflags) extern void send_pio_req(unsigned long port, unsigned long count, int size, paddr_t value, int dir, int df, int value_is_ptr); +void send_timeoffset_req(unsigned long timeoff); extern void handle_mmio(unsigned long gpa); extern void hvm_interrupt_post(struct vcpu *v, int vector, int type); extern void hvm_io_assist(struct vcpu *v); diff --git a/xen/include/asm-x86/time.h b/xen/include/asm-x86/time.h index 731ce9500e..df74cf2962 100644 --- a/xen/include/asm-x86/time.h +++ b/xen/include/asm-x86/time.h @@ -16,4 +16,9 @@ static inline cycles_t get_cycles(void) return c; } +unsigned long +mktime (unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec); + #endif /* __X86_TIME_H__ */ diff --git a/xen/include/public/hvm/ioreq.h b/xen/include/public/hvm/ioreq.h index 4ff8936a5a..646246e854 100644 --- a/xen/include/public/hvm/ioreq.h +++ b/xen/include/public/hvm/ioreq.h @@ -39,6 +39,7 @@ #define IOREQ_TYPE_XOR 4 #define IOREQ_TYPE_XCHG 5 #define IOREQ_TYPE_ADD 6 +#define IOREQ_TYPE_TIMEOFFSET 7 /* * VMExit dispatcher should cooperate with instruction decoder to